<?php

/**
 * @file
 * Administrative page callbacks for the dblog module.
 */

/**
 * Menu callback; displays a listing of log messages.
 *
 * Messages are truncated at 56 chars. Full-length message could be viewed at
 * the message details page.
 *
 * @ingroup logging_severity_levels
 */
function dblog_overview() {
	$filter = dblog_build_filter_query();
	$rows = array();
	$classes = array(
			WATCHDOG_DEBUG     => 'dblog-debug',
			WATCHDOG_INFO      => 'dblog-info',
			WATCHDOG_NOTICE    => 'dblog-notice',
			WATCHDOG_WARNING   => 'dblog-warning',
			WATCHDOG_ERROR     => 'dblog-error',
			WATCHDOG_CRITICAL  => 'dblog-critical',
			WATCHDOG_ALERT     => 'dblog-alert',
			WATCHDOG_EMERGENCY => 'dblog-emerg',
	);

	$build['dblog_filter_form'] = drupal_get_form('dblog_filter_form');
	$build['dblog_clear_log_form'] = drupal_get_form('dblog_clear_log_form');

	$header = array(
			'', // Icon column.
			array('data' => t('Type'), 'field' => 'w.type'),
			array('data' => t('Date'), 'field' => 'w.wid', 'sort' => 'desc'),
			t('Message'),
			array('data' => t('User'), 'field' => 'u.name'),
			array('data' => t('Operations')),
	);

	$query = db_select('watchdog', 'w')->extend('PagerDefault')->extend('TableSort');
	$query->leftJoin('users', 'u', 'w.uid = u.uid');
	$query
	->fields('w', array('wid', 'uid', 'severity', 'type', 'timestamp', 'message', 'variables', 'link'))
	->addField('u', 'name');
	if (!empty($filter['where'])) {
		$query->where($filter['where'], $filter['args']);
	}
	$result = $query
	->limit(50)
	->orderByHeader($header)
	->execute();

	foreach ($result as $dblog) {
		$rows[] = array('data' =>
				array(
						// Cells
						array('class' => 'icon'),
						t($dblog->type),
						format_date($dblog->timestamp, 'short'),
						theme('dblog_message', array('event' => $dblog, 'link' => TRUE)),
						theme('username', array('account' => $dblog)),
						filter_xss($dblog->link),
				),
				// Attributes for tr
				'class' => array(drupal_html_class('dblog-' . $dblog->type), $classes[$dblog->severity]),
		);
	}

	$build['dblog_table'] = array(
			'#theme' => 'table',
			'#header' => $header,
			'#rows' => $rows,
			'#attributes' => array('id' => 'admin-dblog'),
			'#empty' => t('No log messages available.'),
	);
	$build['dblog_pager'] = array('#theme' => 'pager');

	return $build;
}

/**
 * Menu callback; generic function to display a page of the most frequent events.
 *
 * Messages are not truncated because events from this page have no detail view.
 *
 * @param $type
 *   type of dblog events to display.
 */
function dblog_top($type) {

	$header = array(
			array('data' => t('Count'), 'field' => 'count', 'sort' => 'desc'),
			array('data' => t('Message'), 'field' => 'message')
	);
	$count_query = db_select('watchdog');
	$count_query->addExpression('COUNT(DISTINCT(message))');
	$count_query->condition('type', $type);

	$query = db_select('watchdog', 'w')->extend('PagerDefault')->extend('TableSort');
	$query->addExpression('COUNT(wid)', 'count');
	$query = $query
	->fields('w', array('message', 'variables'))
	->condition('w.type', $type)
	->groupBy('message')
	->groupBy('variables')
	->limit(30)
	->orderByHeader($header);
	$query->setCountQuery($count_query);
	$result = $query->execute();

	$rows = array();
	foreach ($result as $dblog) {
		$rows[] = array($dblog->count, theme('dblog_message', array('event' => $dblog)));
	}

	$build['dblog_top_table']  = array(
			'#theme' => 'table',
			'#header' => $header,
			'#rows' => $rows,
			'#empty' => t('No log messages available.'),
	);
	$build['dblog_top_pager'] = array('#theme' => 'pager');

	return $build;
}

/**
 * Menu callback; displays details about a log message.
 */
function dblog_event($id) {
	$severity = watchdog_severity_levels();
	$result = db_query('SELECT w.*, u.name, u.uid FROM {watchdog} w INNER JOIN {users} u ON w.uid = u.uid WHERE w.wid = :id', array(':id' => $id))->fetchObject();
	if ($dblog = $result) {
		$rows = array(
				array(
						array('data' => t('Type'), 'header' => TRUE),
						t($dblog->type),
				),
				array(
						array('data' => t('Date'), 'header' => TRUE),
						format_date($dblog->timestamp, 'long'),
				),
				array(
						array('data' => t('User'), 'header' => TRUE),
						theme('username', array('account' => $dblog)),
				),
				array(
						array('data' => t('Location'), 'header' => TRUE),
						l($dblog->location, $dblog->location),
				),
				array(
						array('data' => t('Referrer'), 'header' => TRUE),
						l($dblog->referer, $dblog->referer),
				),
				array(
						array('data' => t('Message'), 'header' => TRUE),
						theme('dblog_message', array('event' => $dblog)),
				),
				array(
						array('data' => t('Severity'), 'header' => TRUE),
						$severity[$dblog->severity],
				),
				array(
						array('data' => t('Hostname'), 'header' => TRUE),
						check_plain($dblog->hostname),
				),
				array(
						array('data' => t('Operations'), 'header' => TRUE),
						$dblog->link,
				),
		);
		$build['dblog_table'] = array(
				'#theme' => 'table',
				'#rows' => $rows,
				'#attributes' => array('class' => array('dblog-event')),
		);
		return $build;
	}
	else {
		return '';
	}
}

/**
 * Build query for dblog administration filters based on session.
 */
function dblog_build_filter_query() {
	if (empty($_SESSION['dblog_overview_filter'])) {
		return;
	}

	$filters = dblog_filters();

	// Build query
	$where = $args = array();
	foreach ($_SESSION['dblog_overview_filter'] as $key => $filter) {
		$filter_where = array();
		foreach ($filter as $value) {
			$filter_where[] = $filters[$key]['where'];
			$args[] = $value;
		}
		if (!empty($filter_where)) {
			$where[] = '(' . implode(' OR ', $filter_where) . ')';
		}
	}
	$where = !empty($where) ? implode(' AND ', $where) : '';

	return array(
			'where' => $where,
			'args' => $args,
	);
}


/**
 * List dblog administration filters that can be applied.
 */
function dblog_filters() {
	$filters = array();

	foreach (_dblog_get_message_types() as $type) {
		$types[$type] = t($type);
	}

	if (!empty($types)) {
		$filters['type'] = array(
				'title' => t('Type'),
				'where' => "w.type = ?",
				'options' => $types,
		);
	}

	$filters['severity'] = array(
			'title' => t('Severity'),
			'where' => 'w.severity = ?',
			'options' => watchdog_severity_levels(),
	);

	return $filters;
}

/**
 * Returns HTML for a log message.
 *
 * @param $variables
 *   An associative array containing:
 *   - event: An object with at least the message and variables properties.
 *   - link: (optional) Format message as link, event->wid is required.
 *
 * @ingroup themeable
 */
function theme_dblog_message($variables) {
	$output = '';
	$event = $variables['event'];
	// Check for required properties.
	if (isset($event->message) && isset($event->variables)) {
		// Messages without variables or user specified text.
		if ($event->variables === 'N;') {
			$output = $event->message;
		}
		// Message to translate with injected variables.
		else {
			$output = t($event->message, unserialize($event->variables));
		}
		if ($variables['link'] && isset($event->wid)) {
			// Truncate message to 56 chars.
			$output = truncate_utf8(filter_xss($output, array()), 56, TRUE, TRUE);
			$output = l($output, 'admin/reports/event/' . $event->wid, array('html' => TRUE));
		}
	}
	return $output;
}

/**
 * Return form for dblog administration filters.
 *
 * @ingroup forms
 * @see dblog_filter_form_submit()
 * @see dblog_filter_form_validate()
 */
function dblog_filter_form($form) {
	$filters = dblog_filters();

	$form['filters'] = array(
			'#type' => 'fieldset',
			'#title' => t('Filter log messages'),
			'#collapsible' => TRUE,
			'#collapsed' => empty($_SESSION['dblog_overview_filter']),
	);
	foreach ($filters as $key => $filter) {
		$form['filters']['status'][$key] = array(
				'#title' => $filter['title'],
				'#type' => 'select',
				'#multiple' => TRUE,
				'#size' => 8,
				'#options' => $filter['options'],
		);
		if (!empty($_SESSION['dblog_overview_filter'][$key])) {
			$form['filters']['status'][$key]['#default_value'] = $_SESSION['dblog_overview_filter'][$key];
		}
	}

	$form['filters']['actions'] = array(
			'#type' => 'actions',
			'#attributes' => array('class' => array('container-inline')),
	);
	$form['filters']['actions']['submit'] = array(
			'#type' => 'submit',
			'#value' => t('Filter'),
	);
	if (!empty($_SESSION['dblog_overview_filter'])) {
		$form['filters']['actions']['reset'] = array(
				'#type' => 'submit',
				'#value' => t('Reset')
		);
	}

	return $form;
}

/**
 * Validate result from dblog administration filter form.
 */
function dblog_filter_form_validate($form, &$form_state) {
	if ($form_state['values']['op'] == t('Filter') && empty($form_state['values']['type']) && empty($form_state['values']['severity'])) {
		form_set_error('type', t('You must select something to filter by.'));
	}
}

/**
 * Process result from dblog administration filter form.
 */
function dblog_filter_form_submit($form, &$form_state) {
	$op = $form_state['values']['op'];
	$filters = dblog_filters();
	switch ($op) {
		case t('Filter'):
			foreach ($filters as $name => $filter) {
				if (isset($form_state['values'][$name])) {
					$_SESSION['dblog_overview_filter'][$name] = $form_state['values'][$name];
				}
			}
			break;
		case t('Reset'):
			$_SESSION['dblog_overview_filter'] = array();
			break;
	}
	return 'admin/reports/dblog';
}

/**
 * Return form for dblog clear button.
 *
 * @ingroup forms
 * @see dblog_clear_log_submit()
 */
function dblog_clear_log_form($form) {
	$form['dblog_clear'] = array(
			'#type' => 'fieldset',
			'#title' => t('Clear log messages'),
			'#description' => t('This will permanently remove the log messages from the database.'),
			'#collapsible' => TRUE,
			'#collapsed' => TRUE,
	);
	$form['dblog_clear']['clear'] = array(
			'#type' => 'submit',
			'#value' => t('Clear log messages'),
			'#submit' => array('dblog_clear_log_submit'),
	);

	return $form;
}

/**
 * Submit callback: clear database with log messages.
 */
function dblog_clear_log_submit() {
	$_SESSION['dblog_overview_filter'] = array();
	db_delete('watchdog')->execute();
	drupal_set_message(t('Database log cleared.'));
}
